import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.Separator
import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.DialogWrapper

import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.util.elementType
import com.intellij.ui.components.JBTextField
import com.intellij.ui.dsl.builder.Cell
import com.intellij.ui.dsl.builder.panel
import io.ktor.util.reflect.*

import liveplugin.*
import org.jetbrains.annotations.NotNull
import javax.swing.JComboBox
import javax.swing.JComponent

/**
 * 针对若依前后端分离工程（Ruoyi-Vue）的live-plugin插件代码。
 *
 * 需要注意若依自动生成功能有domainName和busiName，domainName即domain类的名称，从表名反推出来，此外还定义了一个业务名busiName，用于前端代码。
 *
 * 功能：
 * 1、发开业务相关类；--完成
 * 2、新建http 接口方法；在js和congtroller类中建立方法。
 * 3、创建mapper方法;在mapper类和mybatis plus文件中建立方法。
 * 4、创建service类方法；在serviceImp和service接口类中建立方法。
 *
 */

if (!isIdeStartup) show("可以使用若依(RuoYi-Vue)插件了！")

/**
 * 打开editor相关代码
 */
val preStr = arrayOf("", "", "", "I", "")
val postStr = arrayOf("Controller.java", "Mapper.java", "ServiceImpl.java", "Service.java", ".java")
registerAction(id = "Open Editor Popup", keyStroke = "ctrl shift 1") { event: AnActionEvent ->
    val actionGroup = PopupActionGroup("若依", AnAction("打开Controller文件") {
        openRuoyiCodeFile(event, 0)
    }, AnAction("打开Mapper类") {
        openRuoyiCodeFile(event, 1)
    }, AnAction("打开ServiceImpl类") {
        openRuoyiCodeFile(event, 2)
    }, AnAction("打开Service接口类") {
        openRuoyiCodeFile(event, 3)
    }, AnAction("打开Domain类") {
        openRuoyiCodeFile(event, 4)
    }, AnAction("打开全部Java类") {
        for (i in 0..4) {
            openRuoyiCodeFile(event, i)
        }
    }, Separator.getInstance(), AnAction("打开js文件") {
        openRuoyiCodeFile(event, 5)
    }, AnAction("打开Vue文件") {
        openRuoyiCodeFile(event, 6)
    },
//            AnAction("关闭全部相关文件") {
//                closeRuoyiCode(it)
//            },
        Separator.getInstance()
    )
    actionGroup.createPopup(event.dataContext).showCenteredInCurrentWindow(event.project!!)
}

// 根据Java类名提取此业务的domain类名。
fun getJavaDomainName(@NotNull name: String): String {
    val keyName = if (name.endsWith(postStr[0])) { //0
        name.substring(0, name.length - 15)
    } else if (name.endsWith(postStr[1])) { //1
        name.substring(0, name.length - 11)
    } else if (name.endsWith(postStr[2])) {//2
        name.substring(0, name.length - 16)
    } else if (name.endsWith(postStr[3])) {//3
        name.substring(1, name.length - 12)
    } else { // 4
        name.substring(0, name.length - 5)
    }
    show("获取domain业务名是：$keyName")
    return keyName
}

// 根据domain类名，获取此业务的其他类名
fun Plugin.getClazzName(domainName: String, index: Int): String {
    return preStr[index] + domainName + postStr[index]
}


fun Plugin.getNames(f: VirtualFile): Map<String, String>? {
    var busiName = ""
    val domainName: String
    if (f.name.endsWith(".java")) {
        domainName = getJavaDomainName(f.name)
        for (en in busiNameMap().entries) {
            if (en.value == domainName) {
                busiName = en.key
                break
            }
        }
    } else if (f.name.endsWith(".vue")) {
        busiName = f.path.substring(0, f.path.indexOfLast { it == '/' })
        busiName = busiName.substring(busiName.indexOfLast { it == '/' } + 1)
        val temp = busiNameMap().get(busiName)// 后续保持domain名称与业务名一致。
        domainName = temp ?: busiName
    } else if (f.name.endsWith(".js")) {
        busiName = f.name.substring(0, f.name.length - 3)
        val temp = busiNameMap().get(busiName)// 后续保持domain名称与业务名一致。
        domainName = temp ?: busiName
    } else {
        show("不支持此文件，请在若依代码页面打开！")
        return null
    }
    return mapOf("busiName" to busiName, "domainName" to domainName)
}


fun Plugin.openRuoyiCode(p: Project, busiName: String, domainName: String, index: Int) {
    if (index <= 4) {
        val clazz = getClazzName(domainName, index)
        debug("打开文件：$clazz")
        val f = PluginUtil.findFileByName(clazz, p)

        p.openInEditor(f.path)
    } else if (index == 5) {
        debug("打开文件：$busiName.js")
        val f = PluginUtil.findFileByName("$busiName.js", p)
        p.openInEditor(f.path)
    } else {
        debug("打开文件：/$busiName/index.vue")
        val tf = PluginUtil.findFileByName("/$busiName/index.vue", p)
        tf.parent.children.forEach { p.openInEditor(it.path) }

    }
}

fun Plugin.closeRuoyiCode(popupEvent: AnActionEvent) {

}

fun Plugin.openRuoyiCodeFile(event: AnActionEvent, index: Int) {
    val project = event.project  // Can be null if there are no open projects.
    if (project == null) {
        show("请打开若依工程!")
        return
    }
    val currentfile = event.virtualFile
    if (currentfile == null) {
        show("请打开一个文件!")
        return
    }
    debug("当前文件是：$currentfile")
    val names = getNames(currentfile)
    if (names == null || names["busiName"] == null || names["domainName"] == null) {
        return
    }
    debug(names.toString())
    openRuoyiCode(project, names["busiName"]!!, names["domainName"]!!, index)

}

/**
 * 创建方法代码
 */

var cmMap = HashMap<String, String>()

registerAction(id = "Create Method Popup", keyStroke = "ctrl shift 2") { event: AnActionEvent ->
    val actionGroup = PopupActionGroup("若依", AnAction("创建Controller方法") {
        val project = event.project  // Can be null if there are no open projects.
        if (project == null) {
            show("请打开若依工程!")
            return@AnAction
        }
        val currentfile = event.virtualFile
        if (currentfile == null) {
            show("请打开一个文件!")
            return@AnAction
        }
        debug("当前文件是：$currentfile")
        val names = getNames(currentfile)
        if (names == null || names["busiName"] == null || names["domainName"] == null) {
            return@AnAction
        }
        ControllerMethodDialog(project!!).showAndGet()
        // openRuoyiCodeFile(event, 0)
        //从editor获取文本 主要是
//        val f = PsiDocumentManager.getInstance(project).getPsiFile(event.editor!!.document)
//
//        f!!.children.forEach { if(it.elementType is com.intellij.psi.impl.java.stubs.) }
        // val ele  = f!!.findElementAt(event.editor!!.getCaretModel().getOffset())
        //  show(ele.toString())

        // 生成字符串

        event.editor!!.document.executeCommand(project, description = "创建Controller方法") {
            insertString(event.editor!!.caretModel.offset, controllerMethod(cmMap))
        }

        //插入到文件内


    }, AnAction("创建Mapper方法") {

    }, AnAction("创建Service方法") {

    }
    )
    actionGroup.createPopup(event.dataContext).showCenteredInCurrentWindow(event.project!!)
}


class ControllerMethodDialog(private val project: Project) : DialogWrapper(project) {
    var methodTypeBox = JComboBox(arrayOf("post", "get"))
    lateinit var nameField: Cell<JBTextField>
    var paramTypeBox = JComboBox(arrayOf("map", "domain", "string"))

    init {
        title = "创建Controller方法!"
        init()
        //addMouseListener()
    }

    override fun createCenterPanel(): JComponent {

        return panel {
            row {
                label("类型：")
                cell(methodTypeBox)
                // checkBox = checkBox("Check to enable option")
            }
            row {
                label("名称：")
                nameField = textField()
            }
            row() {
                label("参数：")
                cell(paramTypeBox)
            }

        }
    }

    override fun doOKAction() {
        // 获取输入值
        val type = methodTypeBox.selectedItem.toString()
        val name = nameField.component.text
        val param = paramTypeBox.selectedItem.toString()
        // 验证
        if (type == "post" && param == "string") {
            show("post方法不支持string参数")
            return
        }
        if (name == null || name == "") {
            show("请输入方法名！")
            return
        }

        super.doOKAction()
        cmMap.put("type", type)
        cmMap.put("name", name)
        cmMap.put("param", param)
        debug(cmMap.toString())

    }

    // 处理取消按钮事件
    override fun doCancelAction() {
        super.doCancelAction()
        show("Cancel")
    }
}

/**
 * 通用代码
 */
fun debug(str: String) {
    show(str)
}

if (!isIdeStartup) show("Loaded 'Open Editor Popup'<br/>Use ctrl+shift+1 to run it")
if (!isIdeStartup) show("Loaded 'Create Method Popup'<br/>Use ctrl+shift+2 to run it")